/*
	Copyright (C) 2011 Salil Bhagurkar

	This file is part of illusion

	illusion is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	illusion is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with illusion. 
	If not, see <http://www.gnu.org/licenses/>.
*/

#include <apimod/apimod.h>
#include <kernel/list.h>
#include <kernel/errors.h>
#include <klib/lib.h>

/*
 * The APIMOD arguments library.
 * Note that arguments must always begin with "-"
 * and the registered argument names must not have a "-"
 */



void add_argument(struct app_arguments *appargs, char *name,
		uint_t type, char is_required, char accepts_value)
{
	struct argument *arg = (struct argument *)malloc(sizeof(struct argument));
	string_copy(arg->name, name, ARG_LEN);
	arg->next = arg->prev = null;
	arg->type = type;
	arg->value_len = 0;
	arg->is_required = is_required;
	arg->requires_value = accepts_value;
	list_attach(appargs->args, appargs->args_tail, arg);
}

static struct argument *get_argument(struct app_arguments *appargs, char *name)
{
	struct argument *arg;
	list_for(appargs->args, arg) {
		if(string_equals(arg->name, name))
			return arg;
	}
	return null;
}

uint_t getnumber(char *buffer);

int parse_arguments(struct app_arguments *appargs, char *str)
{
	char thing[ARG_LEN];
	while((*str) != '\0') {
		str = separate(thing, str, ' ');
		//Check if it's an argument name
		if(thing[0] == '-') {
			struct argument *arg = get_argument(appargs, thing);
			if(!arg) {
				printf("args: Unexpected argument name: %s\n", thing);
				return EPARAM;
			}
			if(arg->requires_value) {
				if((*str) == '\0') {
					printf("args: %s expects a value\n", thing);
					return EPARAM;
				}
				str = separate(thing, str, ' ');
				switch(arg->type) {
				case ARGTYPE_INT:
					arg->value.int_value = getnumber(thing);
					arg->value_len = sizeof(int_t);
					break;
				case ARGTYPE_STRING:
					string_copy(arg->value.string_value, thing, ARG_LEN);
					arg->value_len = string_length(thing);
					break;
				}
			}
		} else {
			printf("args: Stray string: %s\n", thing);
			return EPARAM;
		}

	}
	return 0;
}


static uint_t pow(uint_t x,uint_t y)
{
	uint_t mfact=x;
	if(!(y--))
		return 1;
	while(y--)
		x*=mfact;
	return x;
}

uint_t getnumber(char *buffer)
{
	size_t str_scan=0;
	size_t number_length=0;
	size_t number=0;
	if(*buffer=='0' && *(buffer+1)=='x') {
		buffer+=2;
		number_length = string_length(buffer);
		for(str_scan=0;str_scan<number_length;str_scan++) {
			if(*(buffer+str_scan)>='0' && *(buffer+str_scan)<='9') {
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-'0');
			}
			else if(*(buffer+str_scan)>='A' && *(buffer+str_scan)<='F') {
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-0x37);
			}
			else if(*(buffer+str_scan)>='a' && *(buffer+str_scan)<='f') {
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-0x57);
			}
		}
	} else {
		number_length=string_length(buffer);
		for(str_scan=0;str_scan<number_length;str_scan++) {
			number=number+(pow(10,number_length-str_scan-1))*(*(buffer+str_scan)-'0');
		}
	}
	return number;
}
